package com.helloniu.wb.containers {

import com.helloniu.data.BussinessTypeDef;
import com.helloniu.data.wb.WBStyle;
import com.helloniu.data.wb.info.*;
import com.helloniu.fl.ContextManager;
import com.helloniu.fl.util.Class2;
import com.helloniu.fl.util.Tool;
import com.helloniu.mvc.TController;
import com.helloniu.wb.CursorManager2;
import com.helloniu.wb.UndoManager;
import com.helloniu.wb.tools.DrawingTool;
import com.helloniu.wb.tools.DrawingToolInfo;
import com.helloniu.wb.tools.LaserPenTool;
import com.helloniu.wb.tools.ResizeManager;
import com.helloniu.wb.tools.WBEditorImpl;

import flash.display.Shape;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.ui.Keyboard;

import mx.core.UIComponent;
import mx.events.FlexEvent;

public class BlankPaperWrapper extends UIComponent {
    public function BlankPaperWrapper():void {
        super();

        this.addEventListener(FlexEvent.CREATION_COMPLETE, onCreationComplete);
        this.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);

        shapeMgr = new ShapeManager();
        shapeMgr.setWhiteBoard(this);

        wbinfo = new WhiteBoardInfo();
    }

    // 设置白板的工具栏
    public function setWBToolbar(awbEditor:WBEditorImpl):void {
        this.wbToolbar = awbEditor;
    }

    // 激光笔移动监听
    private function laserPen_mouseMoveHandler(event:MouseEvent):void {
        var pt:Point = new Point(event.stageX, event.stageY);

        pt = globalToLocal(pt);

        if(!isInWB(pt)) {
            return;
        }

        if(laserTool != null) {
            laserTool.setStartPoint(pt);
            laserTool.invalidateDisplayList();

            // @temp tonyy, event
            // ModifyEvent////fireDrawShapeEvent(laserTool);
         }
    }

    // 判断 此点 是否在白板内部
    private function isInWB(pt:Point):Boolean {
        var prect:Rectangle = new Rectangle(0, 0, this.width, this.height);

        return prect.containsPoint(pt);
    }

    /**
     * enableMouseInteraction is by default set to true,
     * when you set it to false the mouse events are ignored
     **/
     public var enableMouseInteraction:Boolean = true;

    /***
     * selectedItem
     *
     * this is for the selectedItem on the Wrapper
     * say you want to delete an item, you select it first
     * and then delete it, or select it first to move it...
     * it is the currently selectedItem
     *
     * selectedItem must extend the com.helloniu.wb.DrawingTool class
     **/

    public function set selectedItem(val:DrawingTool):void {
        _selectedItem = val;

        wbToolbar.setSelectedItem(_selectedItem);

        this.invalidateDisplayList();
    }

    public function get selectedItem():DrawingTool{
        return _selectedItem;
    }

    public function getWBStyle():WBStyle {
        return wbToolbar.getWBStyle();
    }

    public function hideWBStyleEditor():void {
    	wbToolbar.setSelectedItem(null);
    }

    private function onCreationComplete(event:FlexEvent):void{
        systemManager.stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
    }

    private function onKeyUp(event:KeyboardEvent):void{
        if(event.keyCode == Keyboard.DELETE) {
            removeSelectedTool();
        }
    }

    private function onMouseDown(event:MouseEvent):void {
        if(CursorManager2.getToolType() == CursorManager2.PAINT_LASER) {
            return;
        }

        if(CursorManager2.getToolType() == CursorManager2.MODIFY_TOOL) {
            ResizeManager.hideResizeBox();
            return;
        }

        if(!CursorManager2.isPainting()) {
            return;
        }

        // @temp tonnyy, none mode
        if(isNaN(_selectedToolType) || _selectedToolType == ShapeTypeDef.LASER) {
            return;
        }

        if(enableMouseInteraction) {
            startDragging(event);
            // @temp tonyy, add to history
        }
    }

    private function startDragging(event:MouseEvent):void {
        createTool(event);

        systemManager.addEventListener(MouseEvent.MOUSE_MOVE,
            systemManager_mouseMoveHandler, true);
        systemManager.addEventListener(MouseEvent.MOUSE_UP,
            systemManager_mouseUpHandler, true);
        systemManager.stage.addEventListener(Event.MOUSE_LEAVE,
            stage_mouseLeaveHandler);
    }

    private function stopDragging():void {
        systemManager.removeEventListener(MouseEvent.MOUSE_MOVE,
            systemManager_mouseMoveHandler, true);
        systemManager.removeEventListener(MouseEvent.MOUSE_UP,
            systemManager_mouseUpHandler, true);
        systemManager.stage.removeEventListener(Event.MOUSE_LEAVE,
            stage_mouseLeaveHandler);
    }

    private function systemManager_mouseMoveHandler(event:MouseEvent):void {
        var pt:Point = new Point(event.stageX, event.stageY);

        if((!(event.target is DrawingTool)) && this != event.target) {
            return;
        }

        pt = globalToLocal(pt);
        _newTool.setEndPoint(pt);

        if(DrawingToolUtil.isNewToolValid(_newTool)) {
            _newTool.invalidateDisplayList();
        }
    }

    private function systemManager_mouseUpHandler(event:MouseEvent):void {
        stopDragging();

        if(!DrawingToolUtil.isNewToolValid(_newTool)) {
            this.removeChild(_newTool);
        }
        else {
            createToolOver();
        }
    }

    private function createTool(event:MouseEvent):void{
        // no mode or laser mode
        if(isNaN(_selectedToolType) || _selectedToolType == ShapeTypeDef.LASER) {
            return;
        }

        _newTool = DrawingToolUtil.createTool(_selectedToolType, event);

        addChild(_newTool);
    }

    private function stage_mouseLeaveHandler(event:MouseEvent):void {
        stopDragging();
    }

    //OVERRIDDEN METHODS
    override protected function createChildren():void {
        super.createChildren();

        if(_border != null) {
            return;
        }

        // draws white background
        _border = new Shape();
        _border.graphics.clear();
        _border.graphics.beginFill(0xFFFFFF, 1);
        _border.graphics.drawRect(0, 0, BORDER_WIDTH, BORDER_HEIGHT);
        _border.graphics.endFill();

        addChild(_border);
    }

    override protected function measure():void {
        super.measure();
    }

    override protected function updateDisplayList(w:Number, h:Number):void {
        super.updateDisplayList(w, h);

        if(isNaN(w) || isNaN(h)) {
            return;
        }

        _border.graphics.clear();
        _border.graphics.beginFill(0xFFFFFF, 0.1);
        _border.graphics.drawRect(0, 0, w, h);
        _border.graphics.endFill();
    }

////////////public api for toolbar //////////////////////////

    /***
     * selectedTool
     *
     * is here so the user can give
     * the component a selected tool
     * this is the current tool that we are drawing with
     * be it a RectangleTool, LineTool or soon to be something
     * like a gradient Tool or something like that.
     *
     * selectedTool must extend the com.helloniu.wb.DrawingTool class
     **/
    public function set selectedTool2(val:Number):void{
        _selectedToolType = val;
        CursorManager2.removeCursor();
    }

    // 隐藏，删除激光笔
    public function hideLaser():void {
        if(laserTool != null) {
            removeChild(laserTool);
            laserTool = null;

            if(systemManager.hasEventListener(MouseEvent.MOUSE_MOVE)) {
                systemManager.removeEventListener(MouseEvent.MOUSE_MOVE,
                    laserPen_mouseMoveHandler, true);
            }

            // @temp tonyy, event
            // fire RemoveEvent ////fireDrawShapeEvent(laserTool);
        }
    }

    // 显示激光笔
    public function showLaser(addShowListener:Boolean = true):void {
        hideLaser(); // remove old laser

        laserTool = new LaserPenTool();
        laserTool.visible = true;
        addChild(laserTool);

        if(!addShowListener) {
            return;
        }

        if(!systemManager.hasEventListener(MouseEvent.MOUSE_MOVE)) {
            systemManager.addEventListener(MouseEvent.MOUSE_MOVE,
                laserPen_mouseMoveHandler, true);
        }

        // @temp tonyy, event
        // CreateEvent////fireDrawShapeEvent(laserTool);
    }

    public function undo():void {
        UndoManager.undo();
    }

    public function redo():void {
        UndoManager.redo();
    }

    private function addStaticTool(drawingTool:DrawingTool):void {
        addChild(drawingTool);

        //this._aChildrenTools.addItem(drawingTool);// @temp tonyy
        //shapeMgr.addShape(drawingTool.getShapeInfo().shapeID, drawingTool);
        //drawingTool.setupListeners();
    }

    private function createToolOver():void {
        // @temp tonyy, event
        // fire CreateEvent //fireDrawShapeEvent(_newTool);
        _newTool.setupListeners();

        var shapeInfo:ShapeInfo = _newTool.getShapeInfo();

        // update some properties
        shapeInfo.shapeID = wbinfo.generateID();
        shapeInfo.pageNum = wbinfo.getCurrPageNumber();
        shapeInfo.shapeOwner = "tester1";
        shapeInfo.shapeRawData = _newTool.getShapePoints2();

        // 1. add to shape manager
        shapeMgr.addShape(shapeInfo.shapeID, _newTool);

        // 2.
        var createAction:CreateShapeAction = new CreateShapeAction();
        //createAction.shapeInfo = DrawingToolUtil.createShapeInfo(_newTool);
        createAction.shapeInfo = shapeInfo;

        // 3. 把create action加到wbinfo里
        wbinfo.getCurrPage().addShapeInfoAction(createAction);

        // 4. 把create action广播到server 或 其他客户端
Tool.traceT("============createToolOver=========： " + shapeInfo.shapeID +"|"+ shapeInfo.toString());
    }

    public function removeSelectedTool():void {
        if(selectedItem != null) {
            CursorManager2.removeCursor();

            shapeMgr.removeShape(selectedItem.getShapeInfo().shapeID);
            selectedItem = null;
            // @temp tonyy, event
            // RemoveEvent
        }
        else {
            Tool.traceT("----removeSelectedTool--tool--is--null----");
        }
    }
////////////public api for toolbar //////////////////////////

////////////use mvc//////////////////////////
    private function getShapeID():String {
        if(controller == null) {
            return "_shape" + numChildren;
        }

        return controller.getUserID() + "_shape" + numChildren;
    }

    // @temp tonyy
    public function initConnection():void {
        //this.soHandler.addChangeListener(statusChange);

        //var resp:Responder = new Responder(fl_getShapeListResultFunc);
        //ncHandler.call("fl_getShapeList", resp);
    }

    private function fl_getShapeListResultFunc(aa1:* = null, aa2:* =null):void {
        for(var i:int = 0; i < aa1.length; i++) {
           var dinfo:DrawingToolInfo = new DrawingToolInfo();
            dinfo.parseData(aa1[i]);

            addShapeToStage(dinfo)
        }
    }

    private function statusChange(asoHandler:*, pname:String = null,
        oldValue:* = null, newValue:* = null):void
    {
        /*
        if(pname == null) {
            return;
        }

        newValue = asoHandler.getProperty(pname);

        if(pname == "DrawShape") {
            var dinfo:DrawingToolInfo = new DrawingToolInfo();
            dinfo.parseData(newValue);

            addShapeToStage(dinfo);
        }
        else if(pname == "ChangeShape") {
            var sid:String = newValue.shapeID;
            var arr2:Array = newValue.shapePoints;

            var shapeMgr:ShapeManager = ShapeManager.getIns();
            var ctool:DrawingTool = shapeMgr.getShape(sid);

            if(!Tool.comparePointsArray(ctool.getInfo().shapePoints, arr2)) {
                ctool.setShapePoints(Tool.toPointsArray(arr2));
                ctool.invalidateDisplayList();
            }
        }
        */
    }

    private function addShapeToStage(dinfo:DrawingToolInfo):void {
        var shapeOwner:String = dinfo.shapeOwner;
        var lockOwner:String = dinfo.lockOwner;
        var shapeID:String = dinfo.shapeID;
        var shapeClass:String = dinfo.shapeClass;
        var shapePoints:Array = dinfo.shapePoints;
        // lockOwner
        // shapeID

        /*
        if (shapeOwner == _userID) {
            // do nothing
        }
        else if (shapeOwner != _userID) {
            var drawTool:DrawingTool = null;

            if(isLaserTool(drawTool, shapeClass)) {
                showLaser(false);
                drawTool = laserTool;
            }
            else {
                drawTool = Class2.newInstance(shapeClass) as DrawingTool;
                addStaticTool(drawTool);
                drawTool.toolTip = "ShapeOwner[" + shapeOwner + "]";
            }

            drawTool.setShapePoints(shapePoints);
            drawTool.invalidateDisplayList();

            drawTool.setInfo(dinfo);
            ShapeManager.getIns().addShape(dinfo.shapeID, drawTool);
        }
        */
    }

    // show laser
    private function fireDrawShapeEvent(dtool:DrawingTool):void {
        if(controller == null) {
            return;
        }

        if(!isLaserTool(dtool)) {
            dtool.toolTip = "ShapeOwner[" + controller.getUserID() + "]";
        }

        var shapeClassName:String = Class2.getClassName(dtool);
        var shapePoints:Array = Tool.arrayCopy(dtool.getShapePoints2());

        /*
        var shapeID:String = getShapeID();
        var dinfo:DrawingToolInfo = new DrawingToolInfo(_userID, _userID, shapeID,
            shapeClassName, shapePoints);

        dtool.setInfo(dinfo);
        ShapeManager.getIns().addShape(shapeID, dtool);

        var obj:Object = new Object();
        dinfo.writeData(obj);

        soHandler.setProperty("DrawShape", obj); // notify all client
        ncHandler.call("fl_DrawShape", null, obj); // notify server
        */
    }

    private function isLaserTool(dtool:DrawingTool = null, dclass:String = null):Boolean {
        if(dtool == null || dclass == null) {
            return false;
        }

        if(dtool == laserTool) {
            return true;
        }

        if(dclass == Class2.getClassName(dtool)) {
            return true;
        }

        return false;
    }

    public function fireChangeShapeEvent(dtool:DrawingTool):void {
        var arr1:Array = dtool.getInfo().shapePoints;
        var arr2:Array = dtool.getShapePoints2();

        if(!Tool.comparePointsArray(arr1, arr2)) {
            // so sync(key, value)
            var obj:Object = new Object();
            obj.shapeID = dtool.getInfo().shapeID;
            obj.shapePoints = Tool.arrayCopy(arr2);

            // @temp tonyy
            ContextManager.getInstance().getNC().call("fl_ChangeShape", null, obj);// notify server
            ContextManager.getInstance().getSO().setProperty("ChangeShape", obj); // notifiy all client
            dtool.getInfo().shapePoints = Tool.arrayCopy(arr2);
        }
    }

    public function setName(aviewName:String):void {
        viewName = aviewName
    }

    public function getName():String {
        return viewName;
    }

    // called by controller, when c.addViewer is called
    public function setController(c:TController):void {
        controller = c;
    }

    // private
    private function getController():TController {
        return controller;
    }

    public function setEnabled(enb:Boolean = false):void {
        // @temp tonyy
        // this.enabled = enb;
        Tool.traceT("---enabled---: " + enb);
    }

    // called by drawingtool or this.mouse listener
    public function notifyModelInfoChanged(sth:*):void {
        controller.notifyModelInfoChanged(createWBEvent(sth));
    }

    private function createWBEvent(sth:*):Object {
        var obj:Object = new Object();
        // BussinessEvent
        obj.confID = controller.getConfID();
        obj.fromUserID = controller.getUserID()
        obj.toUserIDs = new Array();
        obj.bussinessType = BussinessTypeDef.WHITEBOARD;
        obj.bussinessID = viewName;

        // busssinessdata
        obj.bussinessData = sth; // WBEvent

        return obj;
    }

    // called by controller
    // update model info
    public function updateModelInfo(sth:*):void {
        // viewer execute sth
        Tool.traceT("---viewer do sth--: " + sth);
    }
////////////use mvc//////////////////////////



///////////////use new info structure///////////
    public function populate(awbinfo:WhiteBoardInfo):void {
        wbinfo = awbinfo;

        showCurrentPage();
    }

    public function populateAction(shapeInfoAction:ShapeInfoAction):void {
        if(shapeInfoAction.type == ShapeInfoAction.CREATE) {
            var shapeInfo:ShapeInfo = shapeInfoAction.shapeInfo;
            justAddToStage(shapeInfo);
        }
        else if(shapeInfoAction.type == ShapeInfoAction.MODIFY) {
            // get shape assembly
            shapeMgr.getShape(shapeInfo.shapeID);
            // set shapeInfo
        }
        else if(shapeInfoAction.type == ShapeInfoAction.REMOVE) {
            removeShape(shapeInfo.shapeID);
        }
    }

    private function justAddToStage(shapeInfo:ShapeInfo):void {
        // create shape assembly
        //var dtool:DrawingTool = shapeMgr.createShape2(shapeInfo.shapeType)
        var dtool:DrawingTool = shapeMgr.createShape(shapeInfo.shapeType)

        // just add shape to stage
        addChild(dtool);

        // set shapeInfo
        dtool.setShapeInfo(shapeInfo);
        //dtool.resetDefaultWBStyle();
        dtool.setupListeners();

        shapeMgr.addShape(shapeInfo.shapeID, dtool);
        dtool.invalidateDisplayList();
        Tool.traceT("============justAddToStage=========： " + shapeInfo.shapeID +"|"+ shapeInfo.toString());
    }

    // 创建新图形
    private function createShape(shapeID:String):void {
        // add new shape to shapemanager
        //shapeMgr.addShape();

        // add create shape action to  wbinfo
        //wbinfo.getCurrPage().addShapeInfoAction();

        // notify create shape action
    }

    //显示当前页
    public function showCurrentPage():void {
        shapeMgr.removeAll();

        var wbPage:WhiteBoardPageInfo = wbinfo.getCurrPage();
        var shapeInfoActions:Array = wbPage.getShapeInfoActions();

        // populate new shape
        for(var i:int = 0; i < shapeInfoActions.length; i++) {
            populateAction(shapeInfoActions[i]);
        }

        this.invalidateDisplayList();
    }

    public function getWBInfo():WhiteBoardInfo {
        return wbinfo;
    }

    public function removeShape(shapeID:String):void {
        shapeMgr.removeShape(shapeID);
    }

    /***
     * 这个方法应该在toolbar里就够了，或者是在controller里

    public function showPage(idx:Number):void {
    }

    public function createPage(idx:Number = NaN):void {
    }

    // 删除页
    public function removePage(idx:Number = NaN):void {
    }

    //翻页
    public function gotoPage(idx:Number = NaN):void {
    }

    // 清空页
    public function clearPage(idx:Number = NaN):void {
    }
    // 清空当前页
    private function removeAll():void {
    }

    ***/
///////////////use new info structure///////////

    public var wbinfo:WhiteBoardInfo = null;
    private var shapeMgr:ShapeManager = null;//管理着当前显示的图像

    private var viewName:String;
    private var controller:TController = null;

    private var laserTool:LaserPenTool = null;
    private var _border:Shape;

    /**
     * the tool we are currently drawing
     **/
    private var _newTool:DrawingTool = null;
    private var _selectedItem:DrawingTool;

    private var _selectedToolClass:Class;
    private var _selectedToolType:Number;
    private var historyMCs:Array = new Array();
    private var historyMCIdx:Number = 0;
    private var BORDER_WIDTH:int = 400;
    private var BORDER_HEIGHT:int = 400;

    private var wbToolbar:WBEditorImpl = null;
}
}